package io.github.uicdb.flame_driven.common.block;

import io.github.noeppi_noeppi.libx.base.tile.BlockEntityBase;
import io.github.noeppi_noeppi.libx.base.tile.TickableBlock;
import io.github.noeppi_noeppi.libx.inventory.BaseItemStackHandler;
import io.github.noeppi_noeppi.libx.inventory.IAdvancedItemHandlerModifiable;
import io.github.uicdb.flame_driven.ModUtil;
import io.github.uicdb.flame_driven.common.recipe.ModRecipes;
import io.github.uicdb.flame_driven.common.recipe.SingleInputRecipe;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.function.BinaryOperator;

public class BELifeAggregator extends BlockEntityBase implements TickableBlock {
    protected boolean start;
    protected int timeTicks=0;
    protected SingleInputRecipe selectedRecipe =null;
    protected int degree=0;
    public final BaseItemStackHandler baseItemStackHandler;
    public BELifeAggregator(BlockEntityType<?> type, BlockPos pos, BlockState state) {
        super(type, pos, state);
        baseItemStackHandler= BaseItemStackHandler.builder(2)
                .contentsChanged(slot-> {
                    if(isStart()&&selectedRecipe!=null){
                        setStart(false);
                        selectedRecipe=null;
                        timeTicks=0;
                    }
                    update();
                })
                .build();
    }

    protected int addTime(){
        return timeTicks++;
    }
    protected float getRecipeMulti(){
        return Math.random()>0.3?1:0.7f;
    }
    @Override
    public void tick() {
        degree++;
        if(degree>=360)degree=0;
        if(getLevel() instanceof ServerLevel serverLevel){
            if(isStart()){
                if(checkRecipe(serverLevel))
                {
                    addParticle(serverLevel);
                    if (addTime() >= selectedRecipe.craftTime()) {
                        ItemStack recipeResult=selectedRecipe.assemble(baseItemStackHandler.toVanilla());
                        recipeResult.setCount((int) (recipeResult.getCount()*getRecipeMulti()));
                        baseItemStackHandler.setStackInSlot(1,recipeResult);
                        selectedRecipe = null;
                        timeTicks = 0;
                        setStart(false);
                    }
                    update();
                }
            }
        }
    }
    private void addParticle(ServerLevel serverLevel){
        serverLevel.sendParticles(ParticleTypes.GLOW,getBlockPos().getX()+Math.random(),getBlockPos().getY()+1,getBlockPos().getZ()+Math.random(),1,0,Math.random(),0,0.3f);
        serverLevel.sendParticles(ParticleTypes.SOUL,getBlockPos().getX()+Math.random(),getBlockPos().getY()+1,getBlockPos().getZ()+Math.random(),1,0,Math.random(),0,0.01f);
    }
    private boolean checkRecipe(ServerLevel serverLevel){
        if(selectedRecipe ==null) {
            var present = serverLevel.getRecipeManager().getRecipesFor(ModRecipes.SINGLE_INPUT_RECIPE_RECIPE_TYPE,baseItemStackHandler.toVanilla(),serverLevel).stream().reduce((singleInputRecipe, singleInputRecipe2) -> singleInputRecipe.in().count()>singleInputRecipe2.in().count()?singleInputRecipe:singleInputRecipe2);
             if (present.isEmpty()){
                setStart(false);
                return false;
            }
            present.ifPresent(singleInputRecipe -> selectedRecipe =singleInputRecipe);
        }
        return baseItemStackHandler.getStackInSlot(1).isEmpty();
    }


  private void update(){
        if(level instanceof ServerLevel)
            ModUtil.sendBEUpdate(this);
  }

    @Override
    public AABB getRenderBoundingBox() {
        return INFINITE_EXTENT_AABB;
    }

    public boolean isStart() {
        return start;
    }

    public void setStart(boolean start) {
        this.start=start;
        update();
    }

    @Override
    public void setRemoved() {
        start=false;
        selectedRecipe=null;
        super.setRemoved();
    }

    @Override
    protected void saveAdditional(CompoundTag pTag) {
        pTag.putBoolean("start",start);
        pTag.putInt("timeTicks",timeTicks);
        pTag.put("item",baseItemStackHandler.serializeNBT());
        super.saveAdditional(pTag);
    }

    @Override
    public void load(@NotNull CompoundTag pTag) {
        super.load(pTag);
        start=pTag.getBoolean("start");
        timeTicks=pTag.getInt("timeTicks");
        if(pTag.contains("item")){
            baseItemStackHandler.deserializeNBT(pTag.getCompound("item"));
        }
    }

    @Override
    public void onLoad() {
        super.onLoad();
        if(level instanceof ServerLevel serverLevel)
            checkRecipe(serverLevel);
    }


    @NotNull
    @Override
    public CompoundTag getUpdateTag() {
        var pTag= super.getUpdateTag();
        pTag.putBoolean("start",start);
        pTag.putInt("timeTicks",timeTicks);
        pTag.put("item",baseItemStackHandler.serializeNBT());
        return pTag;
    }

    @Override
    public void handleUpdateTag(CompoundTag tag) {
        super.handleUpdateTag(tag);
    }

    @Nullable
    @Override
    public Packet<ClientGamePacketListener> getUpdatePacket() {
        return  ClientboundBlockEntityDataPacket.create(this);
    }


    public int getRenderRotate() {
        return degree;
    }

    @NotNull
    @Override
    public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
        if(cap.equals(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY))
        return baseItemStackHandler.createCapability().cast();
        return LazyOptional.empty();
    }


}
